from dataclasses import dataclass,field
from abc import ABCMeta, abstractmethod
from typing import List

@dataclass
class CMD_REPLY:
    hex_ascii: int   = 1  
    cmd: List[str]  = field(default_factory=list)
    reply: List[any]  = field(default_factory=list)
    cmd_max_len: int = 20
    multi_packet :int = 0    # 分包
    pass

class isensor(metaclass = ABCMeta):
    # 构造方法
    def __init__(self, sensor_name  ):
        self.sensor_name            = sensor_name
        self.type                   = None
        self.timeout                = 1000  # ms
        self.seq                    = 0
        self.cmd:list               = []
        self.reply:list             = []
        self.cmd_reply              = CMD_REPLY( )
        
    # 抽象方法
    @abstractmethod
    def handle(self):
        pass

    # 抽象方法
    @abstractmethod
    def validate(self, reply,seq):
        pass

    @classmethod
    def set_seq(self, seq):
        self.seq = seq 
        
    @classmethod
    def calc_crc_str(self, string:str):
        data = bytearray.fromhex(string)
        crc = 0xFFFF
        for pos in data:
            crc ^= pos
            for i in range(8):
                if ((crc & 1) != 0):
                    crc >>= 1
                    crc ^= 0xA001
                else:
                    crc >>= 1
        return hex(((crc & 0xff) << 8) + (crc >> 8))

    @classmethod
    def calc_crc_byte(self, byt:bytes):
        data = byt
        crc = 0xFFFF
        for pos in byt:
            crc ^= pos
            for i in range(8):
                if ((crc & 1) != 0):
                    crc >>= 1
                    crc ^= 0xA001
                else:
                    crc >>= 1
        return crc

    @classmethod
    def check_crc_str(self, string:str):
        string_byte = bytearray.fromhex(string)
        data = string_byte[:-2]
        val = string_byte[-2: ]
        crc = 0xFFFF
        for pos in data:
            crc ^= pos
            for i in range(8):
                if ((crc & 1) != 0):
                    crc >>= 1
                    crc ^= 0xA001
                else:
                    crc >>= 1
        if crc>>8 == val[1] and crc&0x00FF == val[0]:
            return True
        return False

    @classmethod
    def check_crc_byte(self, byt:bytes):
        data = byt[:-2]
        val = byt[-2: ]
        crc = 0xFFFF
        for pos in data:
            crc ^= pos
            for i in range(8):
                if ((crc & 1) != 0):
                    crc >>= 1
                    crc ^= 0xA001
                else:
                    crc >>= 1
        if crc>>8 == val[1] and crc&0x00FF == val[0]:
            return True
        return False

class sensor_default(isensor):

    def handle(self,):
        self.cmd_reply.hex_ascii = 1 # hex 1   ascii  2
        self.cmd_reply.cmd = [
				"0103000000044409",
				"0103000000044409"
            ]
        self.cmd_reply.reply = [
				"010308000200030004000573D5",
				"010308000200030004000573D5"
            ]
        self.data_type = 1   
        # self.cmd = ["0103000000044409AA"]
        # self.reply = ["0103000000044409AA"]
        # print(f"sensor_1 handle............{self.cmd}")
        
    def validate(self, reply,seq):
        cmd  = bytearray.fromhex(self.cmd_reply.cmd[seq])
        re   = bytearray.fromhex(reply)
        
        if len(re) < 5:
            return False
        if cmd[0] != re[0] or cmd[1] != re[1]:
            return False
        if 2*(cmd[4]*256+cmd[5]) != re[2]:
            return False
        if not self.check_crc_byte(re)  :
            return False
        # print(f"sensor_hex validate............seq :  {seq}  cmd : {cmd}  rpl : {re}")
        # print(f"sensor_hex validate............cmd : {cmd}")
        # print(f"sensor_hex validate............rpl : {re}")
        return True
        pass
    
    pass

class sensor_hex(isensor):

    def handle(self,):
        self.cmd_reply.hex_ascii = 1 # hex 1   ascii  2
        self.cmd_reply.cmd = [
				"0103000000044409",
				"0103000000044409"
            ]
        self.cmd_reply.reply = [
				"010308000200030004000573D5",
				"010308000200030004000573D5"
            ]
        self.data_type = 1   
        # self.cmd = ["0103000000044409AA"]
        # self.reply = ["0103000000044409AA"]
        # print(f"sensor_1 handle............{self.cmd}")
        
    def validate(self, reply,seq):
        cmd  = bytearray.fromhex(self.cmd_reply.cmd[seq])
        re   = bytearray.fromhex(reply)
        
        if len(re) < 5:
            return False
        if cmd[0] != re[0] or cmd[1] != re[1]:
            return False
        if 2*(cmd[4]*256+cmd[5]) != re[2]:
            return False
        if not self.check_crc_byte(re)  :
            return False
        # print(f"sensor_hex validate............seq :  {seq}  cmd : {cmd}  rpl : {re}")
        # print(f"sensor_hex validate............cmd : {cmd}")
        # print(f"sensor_hex validate............rpl : {re}")
        return True
        pass
    
    pass

class sensor_ascii(isensor):
    def handle(self,):
        self.cmd_reply.hex_ascii = 2 # hex 1   ascii  2
        self.cmd_reply.cmd = [
                "0103000000044409FF"
            ]
        self.cmd_reply.reply = [
                "0103000000044409EE"
            ]
        self.data_type = 2   
        # self.cmd = ["0103000000044409BB"]
        # self.reply = ["0103000000044409BB"]
        # print(f"sensor_2 handle........ {self.cmd}")
        
    def validate(self, reply,seq):

        return True
        pass
    pass

class sensor_enviroFlu(isensor):
    def handle(self,):
        self.cmd_reply.hex_ascii = 1 # hex 1   ascii  2
        self.cmd_reply.cmd = [
                "23000000A8008101",
                "23000000A8008101",
                "23000000A8008101",
                "23000000A8008101",
                "23000000A8008101"
            ]
        self.cmd_reply.reply = [
                "13 11 23 00 00 00 00 00 00 80 1D 01",  #3.54
                "13 11 23 00 00 00 00 00 00 80 99 01", #18.68
                "13 11 23 00 00 00 00 00 00 00 D9 01",  #2.65
                "13 11 23 00 00 00 00 00 00 0F FF 01",  #50
                "13 11 23 00 00 00 00 00 00 0F 40 64 01"
            ]
        self.data_type = 2   
        # self.cmd = ["0103000000044409BB"]
        # self.reply = ["0103000000044409BB"]
        # print(f"sensor_2 handle........ {self.cmd}")
        
    def validate(self, reply,seq):
        cmd  = bytearray.fromhex(self.cmd_reply.cmd[seq])
        re   = bytearray.fromhex(reply)
        if len(re) < 12:
            return False
        if  re[0] != 0x13 and  re[1] != 0x17 and  re[2] != 0x35 and re[-1] != 0x01  :
            return False
        if  len(re) < 12  or len(re) >24:
            return False
        # print(f"sensor_enviroflu validate............seq :  {seq}  cmd : {cmd}  rpl : {re}  re[0] {re[0]}")
        return True
        pass
    pass

class Ramses(isensor):
    def handle(self,):
        self.cmd_reply.hex_ascii = 2 # hex 1   ascii  2
        self.cmd_reply.cmd = ["0103000000044409FF"]
        self.cmd_reply.reply = ["0103000000044409EE"]
        self.data_type = 1   
    def validate(self):
        pass
    pass